pitr.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import { PermissionAction } from '@supabase/shared-types/out/constants'
  2. import { useParams } from 'common'
  3. import { AlertCircle } from 'lucide-react'
  4. import { Alert, AlertDescription, AlertTitle } from 'ui'
  5. import { Admonition } from 'ui-patterns'
  6. import { PageContainer } from 'ui-patterns/PageContainer'
  7. import {
  8. PageHeader,
  9. PageHeaderMeta,
  10. PageHeaderNavigationTabs,
  11. PageHeaderSummary,
  12. PageHeaderTitle,
  13. } from 'ui-patterns/PageHeader'
  14. import { PageSection, PageSectionContent } from 'ui-patterns/PageSection'
  15. import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
  16. import DatabaseBackupsNav from '@/components/interfaces/Database/Backups/DatabaseBackupsNav'
  17. import { PITRNotice } from '@/components/interfaces/Database/Backups/PITR/PITRNotice'
  18. import { PITRSelection } from '@/components/interfaces/Database/Backups/PITR/PITRSelection'
  19. import DatabaseLayout from '@/components/layouts/DatabaseLayout/DatabaseLayout'
  20. import DefaultLayout from '@/components/layouts/DefaultLayout'
  21. import AlertError from '@/components/ui/AlertError'
  22. import { DocsButton } from '@/components/ui/DocsButton'
  23. import NoPermission from '@/components/ui/NoPermission'
  24. import { UpgradeToPro } from '@/components/ui/UpgradeToPro'
  25. import { useBackupsQuery } from '@/data/database/backups-query'
  26. import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
  27. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  28. import { useIsOrioleDbInAws, useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  29. import { DOCS_URL, PROJECT_STATUS } from '@/lib/constants'
  30. import type { NextPageWithLayout } from '@/types'
  31. const DatabasePhysicalBackups: NextPageWithLayout = () => {
  32. return (
  33. <>
  34. <PageHeader>
  35. <PageHeaderMeta>
  36. <PageHeaderSummary>
  37. <PageHeaderTitle>Database Backups</PageHeaderTitle>
  38. </PageHeaderSummary>
  39. </PageHeaderMeta>
  40. <PageHeaderNavigationTabs>
  41. <DatabaseBackupsNav active="pitr" />
  42. </PageHeaderNavigationTabs>
  43. </PageHeader>
  44. <PageContainer>
  45. <PageSection>
  46. <PageSectionContent>
  47. <div className="space-y-8">
  48. <PITR />
  49. </div>
  50. </PageSectionContent>
  51. </PageSection>
  52. </PageContainer>
  53. </>
  54. )
  55. }
  56. DatabasePhysicalBackups.getLayout = (page) => (
  57. <DefaultLayout>
  58. <DatabaseLayout title="Backups">{page}</DatabaseLayout>
  59. </DefaultLayout>
  60. )
  61. const PITR = () => {
  62. const { ref: projectRef } = useParams()
  63. const { data: project } = useSelectedProjectQuery()
  64. const { hasAccess: hasAccessToPitr, isLoading: isLoadingEntitlements } =
  65. useCheckEntitlements('pitr.available_variants')
  66. const isOrioleDbInAws = useIsOrioleDbInAws()
  67. const {
  68. data: backups,
  69. error,
  70. isPending: isLoadingBackups,
  71. isError,
  72. isSuccess,
  73. } = useBackupsQuery({ projectRef })
  74. const isLoading = isLoadingBackups || isLoadingEntitlements
  75. const isEnabled = backups?.pitr_enabled
  76. const isActiveHealthy = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
  77. const { can: canReadPhysicalBackups, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions(
  78. PermissionAction.READ,
  79. 'physical_backups'
  80. )
  81. if (isPermissionsLoaded && !canReadPhysicalBackups) {
  82. return <NoPermission resourceText="view PITR backups" />
  83. }
  84. if (isOrioleDbInAws) {
  85. return (
  86. <Admonition
  87. type="default"
  88. title="Database backups are not available for OrioleDB"
  89. description="OrioleDB is currently in public alpha and projects created are strictly ephemeral with no database backups"
  90. >
  91. <DocsButton abbrev={false} className="mt-2" href={DOCS_URL} />
  92. </Admonition>
  93. )
  94. }
  95. return (
  96. <>
  97. {isLoading && <GenericSkeletonLoader />}
  98. {isError && <AlertError error={error} subject="Failed to retrieve PITR backups" />}
  99. {isSuccess && (
  100. <>
  101. {!isEnabled ? (
  102. <UpgradeToPro
  103. addon={hasAccessToPitr ? 'pitr' : undefined}
  104. source="pitr"
  105. featureProposition="enable Point-in-Time Recovery"
  106. primaryText="Point in Time Recovery is a Pro Plan add-on"
  107. secondaryText={
  108. !hasAccessToPitr
  109. ? 'Roll back your database to a specific second. Starts at $100/month. Pro Plan already includes daily backups at no extra cost.'
  110. : 'Enable the add-on to add point-in-time recovery to your project.'
  111. }
  112. />
  113. ) : !isActiveHealthy ? (
  114. <Alert>
  115. <AlertCircle />
  116. <AlertTitle>
  117. Point in Time Recovery is not available while project is offline
  118. </AlertTitle>
  119. <AlertDescription>
  120. Your project needs to be online to restore your database with Point in Time Recovery
  121. </AlertDescription>
  122. </Alert>
  123. ) : (
  124. <>
  125. <PITRNotice />
  126. <PITRSelection />
  127. </>
  128. )}
  129. </>
  130. )}
  131. </>
  132. )
  133. }
  134. export default DatabasePhysicalBackups